package pro.ticktock.base.tree.impl;

import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import pro.ticktock.base.tree.api.Entry;
import pro.ticktock.base.tree.api.EntryTreeNode;
import pro.ticktock.base.tree.api.HashEntryTreeNode;

import java.util.*;

/**
 * @author lambert
 * @created 18-9-30
 */
public class ListEntryTreeNodeImpl<K, V>
        extends AbstractEntryTreeNode<EntryTreeNode<K, V>, K, V>
        implements EntryTreeNode<K, V>
{
  List<EntryTreeNode<K, V>> childList;
  MultiValuedMap<K, EntryTreeNode<K, V>> childMap;

  public ListEntryTreeNodeImpl() {
    this(null, null);
  }

  public ListEntryTreeNodeImpl(K key, V value) {
    childList = new LinkedList<>();
    childMap = new ArrayListValuedHashMap<>();
    setValue(makeEntry(key, value));
  }

  public void setValue(Entry<K, V> entry) {
    ListEntryTreeNodeImpl<K, V> parent = (ListEntryTreeNodeImpl)getParent();
    if (parent != null) {
      parent.childMap.removeMapping(value.getKey(), this);
      parent.childMap.put(entry.getKey(), this);
    }

    super.setValue(entry);
  }

  @Override
  public Collection<EntryTreeNode<K, V>> getChildListBy(K key) {
    return childMap.get(key);
  }

  @Override
  public Collection<EntryTreeNode<K, V>> removeAllChildBy(K key) {
    Collection<EntryTreeNode<K, V>> childList = childMap.remove(key);
    this.childList.removeAll(childList);
    return childList;
  }

  @Override
  public Collection<EntryTreeNode<K, V>> getChildList() {
    return childList;
  }

  @Override
  public void addChild(int idx, EntryTreeNode<K, V> child) {
    childList.add(idx, child);
    childMap.put(child.getEntryKey(), child);
    child.setParent(this);
  }

  @Override
  public boolean removeChild(EntryTreeNode child) {
    boolean removed = childList.remove(child);
    if (removed) {
      childMap.removeMapping(child.getEntryKey(), child);
      child.setParent(null);
    }
    return removed;
  }

  @Override
  public EntryTreeNode removeChildAt(int idx) {
    EntryTreeNode child = childList.remove(idx);
    childMap.removeMapping(child.getEntryKey(), child);
    return child;
  }

  @Override
  public int getChildCount() {
    return childList.size();
  }

  @Override
  public EntryTreeNode childAt(int index) {
    return childList.get(index);
  }

  @Override
  public int indexOf(EntryTreeNode child) {
    return childList.indexOf(child);
  }

  public void clearChild() {
    childList.forEach(c -> c.setParent(null));
    childList.clear();
    childMap.clear();
  }
}
